library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
use work.alu_type.all;

entity GLX_VLIW is
generic (	numBit	: integer := 32;
		Arch		: integer := 5;
		Ram_Size	: integer := 2;
		Rom_Size : integer := 72);
port (	clock		: in   std_logic;
		reset		: in   std_logic;
		vliw_en		: in   std_logic;
		result		: out std_logic_vector(numBit-1 downto 0);
		result_vliw	: out std_logic_vector(numBit-1 downto 0);
		ALUout		: out std_logic_vector(numBit-1 downto 0);
		ALUout_vliw	: out std_logic_vector(numBit-1 downto 0);
		NewPC		: out std_logic_vector(numBit-1 downto 0)
	);
end GLX_VLIW;

architecture Behavioral of GLX_VLIW is
component dlx_cu is
port (	Clk				: in   std_logic;  -- Clock
		Rst				: in   std_logic;  -- Reset:Active-High
		-- Instruction Register
		IR_IN			: in   std_logic_vector(31 downto 0);
		-- IF Control Signal
		IR_LATCH_EN		: out std_logic;  -- Instruction Register Latch Enable
		NPC_LATCH_EN	: out std_logic;  -- NextProgramCounter Register Latch Enable
		-- ID Control Signals
		RegA_LATCH_EN	: out std_logic;  -- Register A Latch Enable
		RegB_LATCH_EN      : out std_logic;  -- Register B Latch Enable
		RegIMM_LATCH_EN	: out std_logic;  -- Immediate Register Latch Enable
		-- EX Control Signal
		EQ_COND			: out std_logic;  -- Branch if (not) Equal to Zero
		JUMP_EN			: out std_logic;  -- JUMP Enable Signal for PC input MUX
		ALU_OPCODE		: out TYPE_OP;  -- ALU Operation Code
		MUXA_SEL		: out std_logic;  -- MUX-A Sel
		MUXB_SEL		: out std_logic;  -- MUX-B Sel
		ALU_OUTREG_EN	: out std_logic;  -- ALU Output Register Enable
		-- MEM Control Signals
		DRAM_WE		: out std_logic;  -- Data RAM Write Enable
		LMD_LATCH_EN	: out std_logic;  -- LMD Register Latch Enable
		PC_LATCH_EN		: out std_logic;  -- Program Counte Latch Enable
		WB_MUX_SEL		: out std_logic;  -- Write Back MUX Sel
		RF_WE			: out std_logic	  -- Register File Write Enable
		--Registers and Immediate
	);
end component;

component reg is
generic (N : integer :=32);
port (	clock	: in   std_logic;
		reset	: in   std_logic;
		enable	: in   std_logic;
		data_in 	: in   std_logic_vector (N-1 downto 0);
		data_out	: out std_logic_vector (N-1 downto 0)
);
end component;

--component reg_fall is
--generic (N : integer :=32);
--port( 	clock	: in   std_logic;
--		reset	: in   std_logic;
--		enable	: in   std_logic;
--		data_in 	: in   std_logic_vector (N-1 downto 0);
--		data_out	: out std_logic_vector (N-1 downto 0)
--);
--end component;

component npc_adder is
generic (N : integer := 32);
port(	data_in	: in   std_logic_vector (N-1 downto 0);
		vliw_en	: in   std_logic;
		data_out	: out std_logic_vector (N-1 downto 0)
);
end component;

component ROM is
generic (	N_DATA	: natural := 32;
		N_ROWS	: natural := 48;
		N_COLS	: natural := 8 );
port( 	rst			: in   std_logic;
		address		: in   STD_LOGIC_VECTOR (N_DATA-1 downto 0);
		vliw_en		: in   std_logic;
		Instruction	: out STD_LOGIC_VECTOR (N_DATA*2-1 downto 0)
);
end component;

component Register_File is
generic (	N 		: positive := 32;		--number of bits in the registers
		N_ADDR 	: positive := 5);		--address size (determines number of registers)
port(	clock	 		: in   std_logic;
		reset			: in   std_logic;
		vliw_en			: in   std_logic;
		port_S_addr		: in   std_logic_vector (N_ADDR-1 downto 0);
		port_T_addr		: in   std_logic_vector (N_ADDR-1 downto 0);
		port_D_addr		: in   std_logic_vector (N_ADDR-1 downto 0);
		port_S_addr_vliw	: in   std_logic_vector (N_ADDR-1 downto 0);
		port_T_addr_vliw	: in   std_logic_vector (N_ADDR-1 downto 0);
		port_D_addr_vliw	: in   std_logic_vector (N_ADDR-1 downto 0);
		write_D_EN		: in   std_logic;
		write_D_EN_vliw	: in   std_logic;
		port_D_IN		: in   std_logic_vector (N-1 downto 0); 
		port_D_IN_vliw		: in   std_logic_vector (N-1 downto 0); 
		port_S_OUT		: out std_logic_vector (N-1 downto 0); 
		port_S_OUT_vliw	: out std_logic_vector (N-1 downto 0);  
		port_T_OUT		: out std_logic_vector (N-1 downto 0);  
		port_T_OUT_vliw	: out std_logic_vector (N-1 downto 0)   
);
end component;

component muxer is
generic (N : integer := 32);
port(	data_0 	: in   std_logic_vector (N-1 downto 0);
		data_1 	: in   std_logic_vector (N-1 downto 0);
		sel		: in   std_logic;
		output 	: out std_logic_vector (N-1 downto 0)
);
end component;

component arithmetic_logic_unit is
generic (	N : integer := 32;
		M : integer := 5);
port(	left			: in   std_logic_vector (N-1 downto 0);	-- left operand (A or NPC)
		right			: in   std_logic_vector (N-1 downto 0);	-- right operand (B or Imm)
		alu_opcode	: in   TYPE_OP;					-- operation to perform (activates the correct output)
		output		: out std_logic_vector (N-1 downto 0);	-- ALU output
		status		: out std_logic						-- unused (should set the OF flag)
);
end component;

component chk_zero is
generic (N : integer := 32);
port(	data_in	: in std_logic_vector (N-1 downto 0);
		is_zero	: out std_logic
);
end component;

component mux21 is
port(	A : in   std_logic;
		B : in   std_logic;
		S : in   std_logic;
		O : out std_logic
);
end component;

component RAM is
generic (DATA	: integer := 32;
             ADDR	: integer := 8);
port( 	clock		: in   std_logic;
		reset		: in   std_logic;
		vliw_en		: in   std_logic;
		write_en		: in   std_logic;
		write_en_vliw	: in   std_logic;
		addr_in		: in   std_logic_vector (ADDR-1 downto 0);
		addr_in_vliw	: in   std_logic_vector (ADDR-1 downto 0);
		data_in		: in   std_logic_vector (DATA-1 downto 0);
		data_in_vliw	: in   std_logic_vector (DATA-1 downto 0);
		data_out		: out std_logic_vector (DATA-1 downto 0);
		data_out_vliw	: out std_logic_vector (DATA-1 downto 0)
        );
end component;

component splitter is
generic (N : integer := 32);
port (	data_in	: in   std_logic_vector (N-1 downto 0);
		control	: in   std_logic_vector (2 downto 0);
		data_out	: out std_logic_vector (N-1 downto 0)
        );
end component;

	-- IF Control Signal
signal i_IR_latch_enable		: std_logic;	-- Instruction Register Latch Enable
signal i_NPC_latch_enable	: std_logic; 	-- NextProgramCounter Register Latch Enable

signal i_IR_latch_enable_vliw		: std_logic;	-- Instruction Register Latch Enable
	-- ID Control Signals
signal i_RegA_latch_enable	: std_logic;  	-- Register A Latch Enable
signal i_RegB_latch_enable	: std_logic; 	-- Register B Latch Enable
signal i_RegImm_latch_enable	: std_logic; 	-- Immediate Register Latch Enable

signal i_RegA_latch_enable_vliw	: std_logic;  	-- Register A Latch Enable
signal i_RegB_latch_enable_vliw	: std_logic; 	-- Register B Latch Enable
signal i_RegImm_latch_enable_vliw	: std_logic; 	-- Immediate Register Latch Enable
	-- EX Control Signal
signal i_eq_condition		: std_logic;	-- Branch if (not) Equal to Zero
signal i_jump_enable			: std_logic;	-- JUMP Enable Signal for PC input MUX
signal i_ALU_opcode			: TYPE_OP;	-- ALU Operation Code
signal i_MuxA_selection		: std_logic;	-- MUX-A Sel
signal i_MuxB_selection		: std_logic;	-- MUX-B Sel
signal i_ALU_outreg_enable	: std_logic;	-- ALU Output Register Enable

signal i_ALU_opcode_vliw			: TYPE_OP;	-- ALU Operation Code
signal i_MuxB_selection_vliw		: std_logic;	-- MUX-B Sel
signal i_ALU_outreg_enable_vliw	: std_logic;	-- ALU Output Register Enable
	-- MEM Control Signals
signal i_dRAM_wenable		: std_logic;	-- Data RAM Write Enable
signal i_LMD_latch_enable	: std_logic;	-- LMD Register Latch Enable
signal i_PC_latch_enable		: std_logic;	-- Program Counte Latch Enable
signal i_WB_Mux_selection	: std_logic;	-- Write Back MUX Sel
signal i_RF_wenable			: std_logic;	-- Register File Write Enable

signal i_dRAM_wenable_vliw		: std_logic;	-- Data RAM Write Enable
signal i_LMD_latch_enable_vliw		: std_logic;	-- LMD Register Latch Enable
signal i_WB_Mux_selection_vliw	: std_logic;	-- Write Back MUX Sel
signal i_RF_wenable_vliw			: std_logic;	-- Register File Write Enable

signal i_Rs1				: std_logic_vector(4 downto 0);
signal i_Rs2				: std_logic_vector(4 downto 0);
signal i_Rd				: std_logic_vector(4 downto 0);
signal i_Immediate			: std_logic_vector(31 downto 0);

signal i_Rs1_vliw				: std_logic_vector(4 downto 0);
signal i_Rs2_vliw				: std_logic_vector(4 downto 0);
signal i_Rd_vliw				: std_logic_vector(4 downto 0);
signal i_Immediate_vliw			: std_logic_vector(31 downto 0);

-- IF
signal i_PC_reg_out		: std_logic_vector (numBit-1 downto 0);
signal i_PC_plus		: std_logic_vector (numBit-1 downto 0);
signal i_NPC_reg_out	: std_logic_vector (numBit-1 downto 0);
signal i_ROM_out		: std_logic_vector (numBit*2-1 downto 0);
signal i_IR_out			: std_logic_vector (numBit-1 downto 0);

signal i_IR_out_vliw		: std_logic_vector (numBit-1 downto 0);
-- ID
signal i_RF_RegA		: std_logic_vector (numBit-1 downto 0);
signal i_RF_RegB		: std_logic_vector (numBit-1 downto 0);
signal i_RegA_out		: std_logic_vector (numBit-1 downto 0);
signal i_RegB_out		: std_logic_vector (numBit-1 downto 0);
signal i_RegImm_out	: std_logic_vector (numBit-1 downto 0);

signal i_RF_RegA_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_RF_RegB_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_RegA_out_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_RegB_out_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_RegImm_out_vliw		: std_logic_vector (numBit-1 downto 0);

signal i_MuxJAL_selection	: std_logic;
signal i_NPC_plus_four	: std_logic_vector (numBit-1 downto 0);
signal i_towards_rf		: std_logic_vector (numBit-1 downto 0);
-- EXE
signal i_ALU_opL_in		: std_logic_vector (numBit-1 downto 0);
signal i_ALU_opR_in		: std_logic_vector (numBit-1 downto 0);
signal i_ALU_output		: std_logic_vector (numBit-1 downto 0);
signal i_status			: std_logic;
signal i_ALU_reg_out	: std_logic_vector (numBit-1 downto 0);

signal i_ALU_opL_in_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_ALU_opR_in_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_ALU_output_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_status_vliw			: std_logic;
signal i_ALU_reg_out_vliw		: std_logic_vector (numBit-1 downto 0);

signal i_is_zero			: std_logic;
signal i_Cond_out 		: std_logic;
-- MEM
signal i_branch 		: std_logic;
signal i_NPC_final		: std_logic_vector (numBit-1 downto 0);
signal i_RAM_out		: std_logic_vector (numBit-1 downto 0);
signal i_to_mem		: std_logic_vector (numBit-1 downto 0);
signal i_from_mem		: std_logic_vector (numBit-1 downto 0);
signal i_control_in		: std_logic_vector (2 downto 0);
signal i_control_out		: std_logic_vector (2 downto 0);
signal i_LMD_reg_out	: std_logic_vector (numBit-1 downto 0);

signal i_RAM_out_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_to_mem_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_from_mem_vliw		: std_logic_vector (numBit-1 downto 0);
signal i_control_in_vliw		: std_logic_vector (2 downto 0);
signal i_control_out_vliw		: std_logic_vector (2 downto 0);
signal i_LMD_reg_out_vliw	: std_logic_vector (numBit-1 downto 0);
-- WB
signal i_wb_out		: std_logic_vector (numBit-1 downto 0);
signal i_wb_out_vliw		: std_logic_vector (numBit-1 downto 0);

signal i_vliw_en		: std_logic;
begin

i_vliw_en <= vliw_en;

--*************************************************--
--**				Instruction Fetch				**--
--*************************************************--

PC: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_PC_latch_enable,
		data_in	=> i_NPC_final,
		data_out	=> i_PC_reg_out
	);

AdderNPC0: npc_adder generic map (numBit) port
map (	data_in	=> i_PC_reg_out,
		vliw_en	=> i_vliw_en,
		data_out	=> i_PC_plus
	);

RomMemory: ROM generic
map (	N_DATA	=> numBit,
		N_ROWS	=> Rom_Size,
		N_COLS	=> 8 ) port
map ( 	rst			=> reset,
		address		=> i_PC_reg_out,
		vliw_en		=> i_vliw_en,
		Instruction	=> i_ROM_out
	);

--NPC: reg_fall generic map (numBit) port
--map (	clock	=> clock,
--		reset	=> reset,
--		enable	=> i_NPC_latch_enable,
--		data_in	=> i_PC_plus,
--		data_out	=> i_NPC_reg_out
--	);

--latch optimization
NPC_LATCH:process(reset,i_NPC_latch_enable,i_PC_plus)
begin
	if reset = '1' then
		i_NPC_reg_out <= (others => '0');
	else
		if i_NPC_latch_enable = '1' then
			i_NPC_reg_out <= i_PC_plus;
		else
			i_NPC_reg_out <= i_NPC_reg_out;
		end if;
	end if;
end process;	
	
IR: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_IR_latch_enable,
		data_in	=> i_ROM_out(numBit-1 downto 0),
		data_out	=> i_IR_out
	);

	
IR_VLIW: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_IR_latch_enable_vliw,
		data_in	=> i_ROM_out(numBit*2-1 downto numBit),
		data_out	=> i_IR_out_vliw
	);
	

--***************************************************--
--**				Control Unit				**--
--***************************************************--

CU: dlx_cu port 
map (	Clk				=> clock,  				-- Clock
		Rst				=> reset,  				-- Reset:Active-High
		-- Instruction Register
		IR_IN			=> i_ROM_out(numBit-1 downto 0),				-- Input operand
		-- IF Control Signal
		IR_LATCH_EN		=> i_IR_latch_enable,		-- Instruction Register Latch Enable
		NPC_LATCH_EN	=> i_NPC_latch_enable,  	-- NextProgramCounter Register Latch Enable
		-- ID Control Signals
		RegA_LATCH_EN	=> i_RegA_latch_enable,  	-- Register A Latch Enable
		RegB_LATCH_EN     	=> i_RegB_latch_enable,  	-- Register B Latch Enable
		RegIMM_LATCH_EN	=> i_RegImm_latch_enable,  	-- Immediate Register Latch Enable
		-- EX Control Signal
		EQ_COND			=> i_eq_condition,			-- Branch if (not) Equal to Zero
		JUMP_EN			=> i_jump_enable,			-- JUMP Enable Signal for PC input MUX
		ALU_OPCODE		=> i_ALU_opcode,			-- ALU Operation Code
		MUXA_SEL		=> i_MuxA_selection,		-- MUX-A Sel
		MUXB_SEL		=> i_MuxB_selection,		-- MUX-B Sel
		ALU_OUTREG_EN	=> i_ALU_outreg_enable,	-- ALU Output Register Enable
		-- MEM Control Signals
		DRAM_WE		=> i_dRAM_wenable,		-- Data RAM Write Enable
		LMD_LATCH_EN	=> i_LMD_latch_enable,		-- LMD Register Latch Enable
		PC_LATCH_EN		=> i_PC_latch_enable,		-- Program Counte Latch Enable
		WB_MUX_SEL		=> i_WB_Mux_selection,		-- Write Back MUX Sel
		RF_WE			=> i_RF_wenable			-- Register File Write Enable
	);
	
CU_VLIW: dlx_cu port 
map (	Clk				=> clock,  				-- Clock
		Rst				=> reset,  				-- Reset:Active-High
		-- Instruction Register
		IR_IN			=> i_ROM_out(numBit*2-1 downto numBit),				-- Input operand
		-- IF Control Signal
		IR_LATCH_EN		=>  i_IR_latch_enable_vliw,		-- Instruction Register Latch Enable
		NPC_LATCH_EN	=> open,  	-- NextProgramCounter Register Latch Enable
		-- ID Control Signals
		RegA_LATCH_EN	=> i_RegA_latch_enable_vliw,  	-- Register A Latch Enable
		RegB_LATCH_EN     	=> i_RegB_latch_enable_vliw,  	-- Register B Latch Enable
		RegIMM_LATCH_EN	=> i_RegImm_latch_enable_vliw,  	-- Immediate Register Latch Enable
		-- EX Control Signal
		EQ_COND			=> open,			-- Branch if (not) Equal to Zero
		JUMP_EN			=> open,			-- JUMP Enable Signal for PC input MUX
		ALU_OPCODE		=> i_ALU_opcode_vliw,			-- ALU Operation Code
		MUXA_SEL		=> open,		-- MUX-A Sel
		MUXB_SEL		=> i_MuxB_selection_vliw,		-- MUX-B Sel
		ALU_OUTREG_EN	=> i_ALU_outreg_enable_vliw,	-- ALU Output Register Enable
		-- MEM Control Signals
		DRAM_WE		=> i_dRAM_wenable_vliw,		-- Data RAM Write Enable
		LMD_LATCH_EN	=> i_LMD_latch_enable_vliw,		-- LMD Register Latch Enable
		PC_LATCH_EN		=> open,		-- Program Counte Latch Enable
		WB_MUX_SEL		=> i_WB_Mux_selection_vliw,		-- Write Back MUX Sel
		RF_WE			=> i_RF_wenable_vliw			-- Register File Write Enable
	);

--*************************************************--
--**				Instruction Decode				**--
--*************************************************--

ARG_PROC : process (i_IR_out)
begin
	case i_IR_out(31 downto 26) is	-- test on the opcode
		when "000000" => --R-type
			i_Rs1		<= i_IR_out(25 downto 21);
			i_Rs2		<= i_IR_out(20 downto 16);
			i_Rd			<= i_IR_out(15 downto 11);
			i_Immediate	<= (others => '0');
		when "000010" | "000011" | "010011" => --J-type (unconditional)
			i_Rs1		<= (others => '0');			--must be R[0] which should be always 0
			i_Rs2		<= i_IR_out(25 downto 21);	--jalr and jr need this register
			i_Rd			<= (others => '1');			--jal and jalr need this one too
			i_Immediate(31 downto 26)<= (others => i_IR_out(25));
			i_Immediate(25 downto 0) <= i_IR_out(25 downto 0);
		when "000100" | "000101" => --J-type (conditional)
			i_Rs1		<= i_IR_out(25 downto 21);
			i_Rs2		<= (others => '0');
			i_Rd			<= (others => '1');
			i_Immediate(31 downto 16) <= (others => i_IR_out(15));
			i_Immediate(15 downto 0) <= i_IR_out(15 downto 0);
		when "101011" | "101001" | "101000" => --ST type
			i_Rs1		<= i_IR_out(25 downto 21);
			i_Rs2		<= i_IR_out(20 downto 16);
			i_Rd			<= (others => '0');
			i_Immediate(31 downto 16) <= (others => i_IR_out(15));
			i_Immediate(15 downto 0) <= i_IR_out(15 downto 0);
		when others => --I-type
			i_Rs1		<= i_IR_out(25 downto 21);
			i_Rs2		<= (others => '0');
			i_Rd			<= i_IR_out(20 downto 16);
			i_Immediate(31 downto 16) <= (others => i_IR_out(15));
			i_Immediate(15 downto 0)	<= i_IR_out(15 downto 0);
	end case;
end process;


ARG_PROC_VLIW : process (i_IR_out_vliw)
begin
	case i_IR_out_vliw(31 downto 26) is	-- test on the opcode
		when "000000" => --R-type
			i_Rs1_vliw		<= i_IR_out_vliw(25 downto 21);
			i_Rs2_vliw		<= i_IR_out_vliw(20 downto 16);
			i_Rd_vliw			<= i_IR_out_vliw(15 downto 11);
			i_Immediate_vliw	<= (others => '0');
		when "000010" | "000011" | "010011" => --J-type (unconditional)
			i_Rs1_vliw		<= (others => '0');			--must be R[0] which should be always 0
			i_Rs2_vliw		<= i_IR_out_vliw(25 downto 21);	--jalr and jr need this register
			i_Rd_vliw			<= (others => '1');			--jal and jalr need this one too
			i_Immediate_vliw(31 downto 26)<= (others => i_IR_out_vliw(25));
			i_Immediate_vliw(25 downto 0) <= i_IR_out_vliw(25 downto 0);
		when "000100" | "000101" => --J-type (conditional)
			i_Rs1_vliw		<= i_IR_out_vliw(25 downto 21);
			i_Rs2_vliw		<= (others => '0');
			i_Rd_vliw			<= (others => '1');
			i_Immediate_vliw(31 downto 16) <= (others => i_IR_out_vliw(15));
			i_Immediate_vliw(15 downto 0) <= i_IR_out_vliw(15 downto 0);
		when "101011" | "101001" | "101000" => --ST type
			i_Rs1_vliw		<= i_IR_out_vliw(25 downto 21);
			i_Rs2_vliw		<= i_IR_out_vliw(20 downto 16);
			i_Rd_vliw			<= (others => '0');
			i_Immediate_vliw(31 downto 16) <= (others => i_IR_out_vliw(15));
			i_Immediate_vliw(15 downto 0) <= i_IR_out_vliw(15 downto 0);
		when others => --I-type
			i_Rs1_vliw		<= i_IR_out_vliw(25 downto 21);
			i_Rs2_vliw		<= (others => '0');
			i_Rd_vliw			<= i_IR_out_vliw(20 downto 16);
			i_Immediate_vliw(31 downto 16) <= (others => i_IR_out_vliw(15));
			i_Immediate_vliw(15 downto 0)	<= i_IR_out_vliw(15 downto 0);
	end case;
end process;

RF: Register_File generic map (numBit,Arch) port
map (	clock	 		=> clock,
		reset			=> reset,
		vliw_en			=> i_vliw_en,
		port_S_addr		=> i_Rs1,
		port_T_addr		=> i_Rs2,
		port_D_addr		=> i_Rd,
		port_S_addr_vliw	=> i_Rs1_vliw,
		port_T_addr_vliw	=> i_Rs2_vliw,
		port_D_addr_vliw	=> i_Rd_vliw,
		write_D_EN		=> i_RF_wenable,
		write_D_EN_vliw	=> i_RF_wenable_vliw,
		port_D_IN		=> i_towards_rf,
		port_D_IN_vliw		=> i_wb_out_vliw,
		port_S_OUT		=> i_RF_RegA,
		port_S_OUT_vliw	=> i_RF_RegA_vliw,
		port_T_OUT		=> i_RF_RegB,
		port_T_OUT_vliw	=> i_RF_RegB_vliw
	);
	
AdderNPC1: npc_adder generic map (numBit) port
map (	data_in	=> i_NPC_reg_out,
		vliw_en	=> i_vliw_en,
		data_out	=> i_NPC_plus_four
	);

with i_IR_out(31 downto 26) select
	i_MuxJAL_selection <=	'1' when "000011" | "010011", --jal or jalr
						'0' when others;

MUX_JAL: muxer generic map (numBit) port
map (	data_0	=> i_wb_out,
		data_1	=> i_NPC_plus_four,
		sel		=> i_MuxJAL_selection,
		output	=> i_towards_rf
	);

RegA: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_RegA_latch_enable,
		data_in	=> i_RF_RegA,
		data_out	=> i_RegA_out
	);
	
RegA_VLIW: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_RegA_latch_enable_vliw,
		data_in	=> i_RF_RegA_vliw,
		data_out	=> i_RegA_out_vliw
	);

RegB: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_RegB_latch_enable,
		data_in	=> i_RF_RegB,
		data_out	=> i_RegB_out
	);

RegB_VLIW: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_RegB_latch_enable_vliw,
		data_in	=> i_RF_RegB_vliw,
		data_out	=> i_RegB_out_vliw
	);

RegImm: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_RegImm_latch_enable,
		data_in	=> i_Immediate,
		data_out	=> i_RegImm_out
	);
	
RegImm_VLIW: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_RegImm_latch_enable_vliw,
		data_in	=> i_Immediate_vliw,
		data_out	=> i_RegImm_out_vliw
	);

--*************************************************--
--**				Execution Stage				**--
--*************************************************--

MUX_ALU_left: muxer generic map (numBit) port
map (	data_0	=> i_RegA_out,
		data_1	=> i_NPC_reg_out,
		sel		=> i_MuxA_selection,
		output	=> i_ALU_opL_in
	);

--not necessary
--MUX_ALU_left_VLIW: muxer generic map (numBit) port
--map (	data_0	=> i_RegA_out_vliw,
--		data_1	=> i_NPC_reg_out_vliw,
--		sel		=> i_MuxA_selection_vliw,
--		output	=> i_ALU_opL_in_vliw
--	);
i_ALU_opL_in_vliw<= i_RegA_out_vliw;

MUX_ALU_right: muxer generic map (numBit) port
map (	data_0	=> i_RegB_out,
		data_1	=> i_RegImm_out,
		sel		=> i_MuxB_selection,
		output	=> i_ALU_opR_in
	);
	
MUX_ALU_right_VLIW: muxer generic map (numBit) port
map (	data_0	=> i_RegB_out_vliw,
		data_1	=> i_RegImm_out_vliw,
		sel		=> i_MuxB_selection_vliw,
		output	=> i_ALU_opR_in_vliw
	);

ALU: arithmetic_logic_unit generic map (numBit,Arch) port
map (	left			=> i_ALU_opL_in,	-- left operand (A or NPC)
		right			=> i_ALU_opR_in,	-- right operand (B or Imm)
		alu_opcode	=> i_ALU_opcode,	-- operation to perform (activates the correct output)
		output		=> i_ALU_output,	-- ALU output
		status		=> i_status		-- unused (should set the OF flag)
	);

ALU_VLIW: arithmetic_logic_unit generic map (numBit,Arch) port
map (	left			=> i_ALU_opL_in_vliw,	-- left operand (A or NPC)
		right			=> i_ALU_opR_in_vliw,	-- right operand (B or Imm)
		alu_opcode	=> i_ALU_opcode_vliw,	-- operation to perform (activates the correct output)
		output		=> i_ALU_output_vliw,	-- ALU output
		status		=> i_status_vliw		-- unused (should set the OF flag)
	);
	
Zero: chk_zero generic map (numBit) port
map (	data_in	=> i_RegA_out,
		is_zero	=> i_is_zero
	);

i_Cond_out <= i_is_zero xnor i_eq_condition;

RegALU: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_ALU_outreg_enable,
		data_in	=> i_ALU_output,
		data_out	=> i_ALU_reg_out
	);

RegALU_VLIW: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_ALU_outreg_enable_vliw,
		data_in	=> i_ALU_output_vliw,
		data_out	=> i_ALU_reg_out_vliw
	);
	
--*************************************************--
--**				Instruction Fetch				**--
--*************************************************--
	
Mux_preNPC: mux21 port
map (	A	=> '0',
		B	=> i_Cond_out,
		S	=> i_jump_enable,
		O	=> i_branch
	);
	
Mux_NPC: muxer generic map (numBit) port
map (	data_0	=> i_NPC_reg_out,
		data_1	=> i_ALU_reg_out,
		sel		=> i_branch,
		output	=> i_NPC_final
	);

with i_IR_out(31 downto 26) select
	i_control_in <=	"101" when "101000", --sb
					"110" when "101001", --sh
					"111" when "101011", --sw
					"000" when others;   

with i_IR_out_vliw(31 downto 26) select
	i_control_in_vliw <=	"101" when "101000", --sb
					"110" when "101001", --sh
					"111" when "101011", --sw
					"000" when others;   
	
SPLIT_IN: splitter generic map(numBit) port 
map (	data_in	=> i_RegB_out,
		control	=> i_control_in,
		data_out	=> i_to_mem
        );

SPLIT_IN_VLIW: splitter generic map(numBit) port 
map (	data_in	=> i_RegB_out_vliw,
		control	=> i_control_in_vliw,
		data_out	=> i_to_mem_vliw
        );

iRAM: RAM generic map (numBit,Ram_Size) port
map ( 	clock	=> clock,
		reset	=> reset,
		vliw_en		=> i_vliw_en,
		write_en		=> i_dram_wenable,
		write_en_vliw	=> i_dram_wenable_vliw,
		addr_in		=> i_ALU_reg_out(Ram_Size-1 downto 0),
		addr_in_vliw	=> i_ALU_reg_out_vliw(Ram_Size-1 downto 0),
		data_in		=> i_to_mem,
		data_in_vliw	=> i_to_mem_vliw,
		data_out		=> i_RAM_out,
		data_out_vliw	=> i_RAM_out_vliw
        );

SPLIT_OUT: splitter generic map (numBit) port
map (	data_in	=> i_RAM_out,
		control	=> i_control_out,
		data_out	=> i_from_mem
        );
	
SPLIT_OUT_VLIW: splitter generic map (numBit) port
map (	data_in	=> i_RAM_out_vliw,
		control	=> i_control_out_vliw,
		data_out	=> i_from_mem_vliw
        );

with i_IR_out(31 downto 26) select
	i_control_out <= 	"101" when "100000", --lb
					"110" when "100001", --lh
					"111" when "100011", --lw
					"001" when "100100", --lbu
					"010" when "100101", --lhu
					"000" when others;    

with i_IR_out_vliw(31 downto 26) select
	i_control_out_vliw <= 	"101" when "100000", --lb
						"110" when "100001", --lh
						"111" when "100011", --lw
						"001" when "100100", --lbu
						"010" when "100101", --lhu
						"000" when others; 

LMD: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_LMD_latch_enable,
		data_in	=> i_from_mem,
		data_out	=> i_LMD_reg_out
	);
	
LMD_VLIW: reg generic map (numBit) port
map (	clock	=> clock,
		reset	=> reset,
		enable	=> i_LMD_latch_enable_vliw,
		data_in	=> i_from_mem_vliw,
		data_out	=> i_LMD_reg_out_vliw
	);

--*************************************************--
--**					Write Back				**--
--*************************************************--

Mux_WB: muxer generic map (numBit) port
map (	data_0	=> i_LMD_reg_out,
		data_1	=> i_ALU_reg_out,
		sel		=> i_wb_mux_selection,
		output	=> i_wb_out
	);
	
Mux_WB_VLIW: muxer generic map (numBit) port
map (	data_0	=> i_LMD_reg_out_vliw,
		data_1	=> i_ALU_reg_out_vliw,
		sel		=> i_wb_mux_selection_vliw,
		output	=> i_wb_out_vliw
	);

result <= i_wb_out;
result_vliw <= i_wb_out_vliw;
NewPC <= i_NPC_reg_out;
ALUout <= i_ALU_reg_out;
ALUout_vliw <= i_ALU_reg_out_vliw;
end Behavioral;
